// 学习目标
// 能够说出什么是DOM
// 能够获取页面元素
// 能够给元素注册事件
// 能够操作DOM元素的属性
// 能够创建元素
// 能够操作DOM节点

// DOM主要掌握以下知识点：获取元素、事件基础、操作元素、节点操作

// DOM常见名词：文档、元素、节点
// 一个页面就是一个文档 DOM中用document表示   页面中所有标签都是元素 DOM中用element表示  网页中所有内容都是节点（标签属性文本注释） DOM中用node表示
// 以上的dom都看成是对象
// nodeType属性值


//如何获取元素、操作元素 、添加事件、操作节点
console.log('获取元素：ID获取、标签名、通过HTML5新增的方法获取、特殊元素获取----------------------------------------------');


console.log('id获取--------------');

document.getElementById('参数')  //参数是大小写敏感字符串 返回一个元素对象
// console.dir()能够更好的打印返回的元素对象 更好的查看里面的属性和方法


console.log('标签名获取-----------------------');

document.getElementsByTagName('标签名') //返回带有指定标签名的对象的集合
// 得到的是一个对象的集合 所以想要操作里面的元素就需要遍历
// 得到元素对象是动态的
// 如果页面中只有一个li 返回的还是伪数组的形式  （伪元素是指不能调用数组的一些方法 如push（））
// 如果页面中没有这个元素 返回的是空的伪数组

// 可以通过某个父元素来获取内部所有指定标签名的子元素
element.getElementsByTagName('标签名') 
// 注意父元素必须是单个对象

// H5新增方法  根据类名获取元素的集合
document.getElementsByClassName('box')

// H5新增querySelector 不管是什么选择器直接给选择出来 
document.querySelector('选择器') //类选择器 标签选择器  id选择器都能够给选择出来  只返回的是第一个对象
var box = document.querySelector('.box') //需要声明是什么选择器
var nav = document.querySelector('#nav') 

document.querySelectorAll() //返回指定选择器的所有元素对象集合



//获取特殊元素 body和html
// 获取body
var bodyEle = document.body  //获取body
console.log(bodyEle);
var htmlEle = document.documentElement  //获取整个html
console.log(htmlEle);


console.log('事件设置----------------------------------------------------------------------');

//事件三要素  事件有三部分组成 事件源 事件类型 事件处理程序
// 事件源 事件被触发的对象  谁被触发了 比如按钮
// 事件类型 什么样的事件被触发了  比如鼠标点击 鼠标经过 还是键盘按下 
// 事件处理程序  通过一个函数赋值的方式完成


// 设置事件的方式
// 1、获取事件源 通过queryselector等方式获取元素
// 2、绑定事件 注册事件  即给元素添加事件
// 3、添加事件处理程序  匿名函数的方式

// 我们可以利用DOM属性来改变元素

// 改变元素内容 
// 使用element.innerText 不识别html标签  同时空格和换行也会去掉
// element.innerHTML 会显示html标签 同时保留空格和换行
// 例如 
var div = document.querySelector('div');
div.innerHTML = '<strong> 今天是 </strong> 2022年'     //这个会按原样展示 不识别html标签
div.innerText //效果一样

// 改变元素属性 
// 直接获取元素之后 然后直接   元素.属性 =   进行修改即可



// 修改表单属性  表单属性比较特殊需要单独拿出来说   主要是 type value checked selected disabled专有的   两个小案例 按钮禁用和隐藏密码明文
// 表单的value就相当于innertext  即表单中的文字信息

console.log('操作样式的方法-----------------------------------------------------------------------------------------');

// 修改样式属性  通过js修改元素的大小 颜色 位置等样式
// 1 当修改样式比较少的时候  通过element.style 行内样式操作
// 2 element.className 类名样式操作

var div = document.querySelector('div');
div.onclick = function(){
    this.style.backgroundColor='purple';   //注意和css写法不同  css中是background-color  需要采取驼峰命名法
}//点击的时候将其样式修改为紫色

// js修改之后是行内样式 css权重比较高

//样式比较多的时候 可以通过element.className修改
// 定义一个类 刚开始的时候先不给 然后在触发了相应的操作之后  给该元素增加该类

this.className='定义的类名';  //注意这个是类名 会覆盖之前的 需要多类名的情况下 
this.className='类名1 类名2';




console.log('属性值操作--------------------------------------------------------------------------------------------------------------------------');
// 获取属性的方式有两种
// 1、element.属性   注意这种方式没法获取自定义属性
// 2、element.getAttribute('属性')   这种方式兼容性比较好
// 区别 : element.属性获取的是内置的属性 ，而element.getAttribute() 主要获得的是自定义属性 (属性的键和值是可以自己定义的)

//对应设置属性值也有两种方法
// 1、element.属性= '值';
// 2、element.setAttribute('属性','值');  主要针对于自定义属性 也可以设置class
element.setAttribute('class','新类名')  //效果等同于  element.className='新类名'

//移除属性
element.removeAttribute('属性');

// 使用自定义属性的目的是：为了保存并使用数据，有些数据可以保存到页面中而不用保存到数据库中
// 因为自定义属性和内置属性之间会产生歧义,因此 H5中规定了自定义属性 需要使用data-开头做为属性名 并且赋值
<div data-index='1' data-list-name='andy'> </div>
H5还新增了 element.dataset.自定义属性名  或者element.dataset['自定义属性名']   dataset是一个集合里卖存放了所有以data开头的自定义属性
console.log(div.dataset.index);
console.log(div.dataset['index']);
console.log(div.dataset.listName); //注意这里必须使用驼峰命名法

console.log('节点操作---------------------------------------------------------------------------');
// 已经有了以上的获取元素的方法,为什么还需要节点操作呢?
// 节点操作：利用父子兄弟节点关系获取元素
//所有内容都是节点：元素节点 属性节点 文本节点

节点至少有以下nodeType(节点类型)、nodeName(节点名称)、nodeValue(节点值)
元素节点 nodeType=1  //实际开发中，节点操作主要操作的是元素节点
属性节点 nodeType=2
文本节点 nodeType=3(文本节点包含文字 空格 换行等)

console.log('父子节点-----------');

获取父节点： 子节点名.parentNode 得到的是离元素最近的父节点，找不到就返回null
获取子节点： 父节点名.childNodes 得到所有的子节点 包含：元素节点、文本节点等等如换行  实际开发时操作的是元素节点 如果需要获得里面的元素节点需要使用nodeType来区分
            父节点名.children 只读属性 只返回所有子元素节点 其余节点不返回 ,返回的是伪数组
获取第一个子节点：父节点名.firstChild 返回第一个子节点，找不到则返回null。同样也是包含所有节点（元素、文本都有）
获取最后一个子节点：父节点名.lastChild 也包含文本节点
获取第一个子元素节点： 父节点名.firstElementChild   ie9以上才支持
获取最后一个子元素节点： 父节点名.lastElementChild  ie9以上才支持
// 实际开发中使用的是children[0]  既没有兼容性问题有返回第一个子元素

console.log('兄弟节点-----------');
获取下一个兄弟节点：nextSibling 包含元素节点或者文本节点等等所有节点  一次获取一个
获取上一个兄弟节点：previousSibling 同上
获取下一个兄弟元素节点：nextElementSibling 只包含元素节点
获取上一个兄弟元素节点：previousElementSibling 只包含元素节点

解决方法是 封装一个函数
function getNextElementSibling(element){
    var el=element;
    while(el=el.nextSibling){ //执行获取这个的兄弟元素 这里不是等于  比如先获取文本节点 然后再获取元素节点
        if(el.nodeType===1){
            return el;
        }
        return null; //没有找到相邻兄弟节点
    }

}


console.log('创建和添加节点------------------------------------------');
创建节点在评论中会用到 比如说当提交评论之后就会添加上去
创建节点使用document.createElement('li') 创建了li元素节点
然后进行添加节点 Node.appendChild(child) 会添加到元素末尾，类似于CSS的after伪元素 如ul.appendChild('li')
Node.insertBefore(child,指定元素) 将一个节点添加到父节点的指定子节点前面 类似于css里面的before伪元素

console.log('删除节点-----------------------------------------------');  //删除的是子节点
Node.removeChild(child) //方法从DOM中删除一个子节点，返回删除的节点


console.log('复制节点，克隆节点------------------------------');
Node.cloneNode()  //方法返回调用该方法的节点的一个副本。也称克隆节点/拷贝节点 克隆完之后需要添加节点
注意括号如果为空，或者false 浅拷贝 只复制标签不复制里面的文本内容等
Node.cloneNode(true) 深拷贝 复制标签里面的内容

